package com.fractalist.base.core.web.interceptor;


import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;

import com.fractalist.base.core.constants.SystemConstants;
import com.fractalist.base.core.utils.DateUtils;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ValidationAware;
import com.opensymphony.xwork2.interceptor.Interceptor;


/**
 * 上传文件的过滤器类，文件上传后将文件名，文件大小作为参数传递到action中
 * 
 * @author radio
 *
 */
public class FtadFileUploadInterceptor implements Interceptor {

	private static final long serialVersionUID = 1L;

	private static final Logger log = Logger
			.getLogger(FtadFileUploadInterceptor.class);

	/**
	 * 文件大小限制
	 */
	private long fileSize = SystemConstants.FILE_UPLOAD_SIZE;

	/**
	 * 文件类型集合
	 */
	private Set<String> fileTypeSet = new HashSet<String>();

	/**
	 * 文件类型分隔符，多个以","隔开
	 */
	private static final String DEFAULT_DELIMITER = ",";

	public void init() {

	}

	/**
	 * 设置允许的文件后缀名，将配置中以“,”分隔的文件后缀名封装到set中
	 * @param allowedType
	 */
	public void setAllowedType(String allowedType) {
		if (allowedType != null) {
			StringTokenizer stringTokenizer = new StringTokenizer(allowedType,
					DEFAULT_DELIMITER);
			while (stringTokenizer.hasMoreTokens()) {
				String nextToken = stringTokenizer.nextToken().toLowerCase()
						.trim();
				if (nextToken.length() > 0) {
					fileTypeSet.add(nextToken);
				}
			}
		}
	}

	public void setFileSize(long fileSize) {
		this.fileSize = fileSize;
	}

	@SuppressWarnings("unchecked")
	public String intercept(ActionInvocation invocation) throws Exception {
		String uploadFileURL = null;
		ActionContext ac = invocation.getInvocationContext();
		HttpServletRequest request = (HttpServletRequest) ac
				.get(ServletActionContext.HTTP_REQUEST);
		if (!(request instanceof MultiPartRequestWrapper)) {
			//if (log.isDebugEnabled()) {
			//	log.debug("webwork.messages.bypass.request");
			//}

			return invocation.invoke();
		}

		ActionSupport action = (ActionSupport) invocation.getAction();
		ValidationAware validation = null;

		if (action instanceof ValidationAware) {
			validation = (ValidationAware) action;
		}

		MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;

		if (multiWrapper.hasErrors()) {
			for (Iterator errorIter = multiWrapper.getErrors().iterator(); errorIter
					.hasNext();) {
				String error = (String) errorIter.next();

				if (validation != null) {
					validation.addActionError(error);
				}

				log.error(error);
			}
		}

		Enumeration fileParameterNames = multiWrapper.getFileParameterNames();

		while (fileParameterNames.hasMoreElements()) {
			// get the value of this input tag，inputName=？
			String inputName = (String) fileParameterNames.nextElement();

			// get the content type contentType=?
			String[] contentType = multiWrapper.getContentTypes(inputName);

			if (isNonEmpty(contentType)) {
				// get the name of the file from the input tag
				String[] fileName = multiWrapper.getFileNames(inputName);

				if (isNonEmpty(fileName)) {
					// Get a File object for the uploaded File
					File[] files = multiWrapper.getFiles(inputName);
					if (files != null) {
						for (int index = 0; index < files.length; index++) {

							if (acceptFile(files[0], contentType[0], action)) {
								// 上传图片
								try {
									uploadFileURL = doUpload(files[0],
											fileName[0]);
									Map map = ac.getParameters();
									map.put("uploadFileURL", uploadFileURL);
									map
											.put("uploadFileSize", files[0]
													.length());
									map.put("uploadFileName", fileName[0]);
								} catch (Exception e) {
									action
											.addActionError("fileupload.upload.error");
								}
							}
						}

					}
				} else {
					log.error("file is empty");
				}
			} else {
				log.error("contentType is empty");
			}
		}
		String result = invocation.invoke();

		// cleanup
		// deleTempFile(uploadPath);
		fileParameterNames = multiWrapper.getFileParameterNames();
		while (fileParameterNames != null
				&& fileParameterNames.hasMoreElements()) {
			String inputValue = (String) fileParameterNames.nextElement();
			File[] file = multiWrapper.getFiles(inputValue);
			for (int index = 0; index < file.length; index++) {
				File currentFile = file[index];
				log.info("webwork.messages.removing.file");

				if ((currentFile != null) && currentFile.isFile()) {
					currentFile.delete();
				}
			}
		}
		return result;

	}

	/**
	 * 校验文件是否能够上传，是否超过大小限制，是否为允许文件类型限制
	 * 
	 * @param file			文件对象
	 * @param contentType	文件类型
	 * @param action		错误信息保存在ActionError中
	 * @return
	 */
	protected boolean acceptFile(File file, String contentType,
			ActionSupport action) {

		// If it's null the upload failed
		if (file == null) {
			action.addActionError("fileupload.filenull");
			log.error("file is null");
			return false;
		}
		if (fileSize < file.length()) {

			action.addActionError("fileupload.filesize");
			log.error("file size is not match");
			return false;
		}
		if ((!fileTypeSet.isEmpty())
				&& (!fileTypeSet.contains(contentType.toLowerCase()))) {

			action.addActionError("fileupload.filetype");
			log.error("file type is not match");
			return false;
		}

		return true;
	}

	/**
	 * 上传文件，服务器上文件名为当前日期(yyyyMMdd)+随机数+原文件后缀名
	 * 
	 * @param file		要上传的文件对象
	 * @param fileName	上传的文件名
	 * @return			文件的服务器访问url
	 * @throws IOException
	 */
	private String doUpload(File file, String fileName) throws IOException {
		// 构建文件名
		Date currenTime = new Date();
		Random random = new Random();

		StringBuffer filePath = new StringBuffer(
				SystemConstants.UPLOAD_SERVER_PATH).append(
				DateUtils.format(currenTime, "yyyyMMdd")).append("/");
		StringBuffer currenFileName = new StringBuffer(DateUtils.format(
				currenTime, "HHmmss")).append(random.nextInt(10000)).append(
				getFileappfix(fileName));

		String localPathName = filePath.append(currenFileName).toString();
		String serverURL = localPathName.replaceFirst(
				SystemConstants.UPLOAD_SERVER_PATH,
				SystemConstants.UPLOAD_WEB_URL);
		FileUtils.copyFile(file, new File(localPathName));
		return serverURL;

	}

	/**
	 * 判断数组是否为空
	 * @param objArray	要检查的数组
	 * @return
	 */
	private static boolean isNonEmpty(Object[] objArray) {
		boolean result = false;
		for (int index = 0; index < objArray.length && !result; index++) {
			if (objArray[index] != null) {
				result = true;
			}
		}
		return result;
	}

	/**
	 * 取得文件的后缀名
	 * @param fileName		文件名
	 * @return				返回文件后缀名
	 */
	protected String getFileappfix(String fileName) {
		int index = fileName.lastIndexOf(".");
		return fileName.substring(index, fileName.length()).intern();
	}

	public void destroy() {
		// TODO Auto-generated method stub

	}
}
